#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "ImaGlobals.h"
#include "ImaConstants.h"
#include "ImaConf.h"
#include "ImaDbInterface.h"
#include "ImaInfoRecipient.h"
#include "ImaEmailNotifier.h"

/******************************************************************************
* Globals declared here
******************************************************************************/
ImaLogger* gpLogger = NULL;
ImaDbInterface* gpDbInterface = NULL;
ImaMqInterface* gpMqInterface = NULL;
ImaConf* gpConf = NULL;

void destroy_globals() {
	LOG(debug, __FILE__, __LINE__, "destroy_globals called");

	delete gpConf;
}

/* Function 	:	daemonize
 * Description	:	this function will demonize the process
 * Parametres 	: 	file descriptor, event and query
 * Return values:
 */
int daemonize(int nNochdir, int nNoclose) {
	int nfd;
	
	// create a new process and exit
	switch (fork()) {
		case -1:	//error 
			std::cout<<"error\n";
			return (-1);
		case 0:	//child process
			std::cout<<"child process\n";
			break;
		default: //parent process
			std::cout<<"parentprocess\n";
			_exit(0);
	}
	
	// run the program in a new session
	if(setsid() == -1) {
		std::cout<<"setsid failed\n";
		return (-1);
	}
	
	// change the dierctory to '/'
	if(!nNochdir) {
		std::cout<<"calling chdir\n";
		(void)chdir("/");
	}
	
	if(!nNoclose && (nfd = open("/dev/null", O_RDWR, 0)) != -1) {
		(void)dup2(nfd, STDIN_FILENO);
		(void)dup2(nfd, STDOUT_FILENO);
		(void)dup2(nfd, STDERR_FILENO);
		if (nfd > 2) {
			(void)close(nfd);
		}
	}

	std::cout<<"will return 0 i.e. success\n";
	return (0);
}

int ima_init_globals(char* pConfFilename) {
	gpConf = new ImaConf(pConfFilename);
	if(gpConf->parseConfFile() != 0) {
		//LOG(error, "Failed to parse conf file");
		fprintf(stderr, "Failed to parse conf file");
		exit(EXIT_FAILURE);
	}

	gpLogger = ImaLogger::getInstance("log4cpp.properties");

	if(gpLogger == NULL) {
		return -1;
	}

	char log_msg[1024];
	sprintf(log_msg, "inside ima_init_globals");
	LOG(debug, __FILE__, __LINE__, log_msg);

	gpDbInterface = ImaDbInterface::getInstance(*gpConf);
	if(gpDbInterface == NULL) {
		LOG(error, __FILE__, __LINE__, "Failed to connect to DB");
		return -1;
	}

	gpMqInterface = ImaMqInterface::getInstance(*gpConf);
	if(gpMqInterface == NULL) {
		LOG(error, __FILE__, __LINE__, "Failed to connect to Message queues");
		return -1;
	}
	
	return 0;
}

void send_new_passwords() {
	LOG(info, __FILE__, __LINE__, "send_new_passwords called");

	char buf[MSGQBUFSZ];
	char emailId[256];
	char newPassword[256];
	char log_msg[1024];

	while(gpMqInterface->deqeueNewPassword(buf) == true) {
		char log_msg[1024];
		char* p = NULL;
		sprintf(log_msg, "Buffer fetched from new passwords message queue %s", buf);
		LOG(debug, __FILE__, __LINE__, log_msg);
		if((p = strstr(buf, "#")) != NULL) {
			size_t len = p - buf;
			strncpy(emailId, buf, len);
			emailId[len] = '\0';

			strcpy(newPassword, p+1);

			ImaEmailNotifier emailNotifier(std::string(gpConf->mSmtpHost), std::string(gpConf->mSmtpUsername), std::string(gpConf->mSmtpPassword));
			emailNotifier.init();
			char msg_body[2048];
			sprintf(msg_body, "Dear %s,\n\n%s %s\n\nRegards,\nIamAliv Team", emailId, MSG_BODY_NEW_PASSWORD, newPassword);
			if(false == emailNotifier.notify(MSG_SUB_NEW_PASSWORD, msg_body, emailId)) {
				LOG(error, __FILE__, __LINE__, "Failed to send new password to the user");
			} else {
				LOG(debug, __FILE__, __LINE__, "Sent the new password to the user");
			}
		} else {
			sprintf(log_msg, "Erroneous message dequeued from the message queue; Message: %s", buf);
			LOG(error, __FILE__, __LINE__, log_msg);
		}
	}
}

void send_conf_codes() {
	LOG(info, __FILE__, __LINE__, "send_conf_codes called");

	char buf[MSGQBUFSZ];
	char emailId[256];
	char confCode[256];

	while(gpMqInterface->deqeueConfCode(buf) == true) {
		char log_msg[1024];
		sprintf(log_msg, "Fetched from conf code message queue %s", buf);
		LOG(debug, __FILE__, __LINE__, log_msg);
		char* p = NULL;
		if((p = strstr(buf, "#")) != NULL) {
			size_t len = p - buf;
			strncpy(emailId, buf, len);
			emailId[len] = '\0';

			p = p+1;
			char* p1 = strstr(p, "#");
			if(p1 != NULL) {
				len = p1-p;
				strncpy(confCode, p, len);
				confCode[len] = '\0';
			}

			bool bEmailAndImSame = true;

			if(strcmp(p1+1, "1") == 0) {
				bEmailAndImSame = true;
			} else {
				bEmailAndImSame = false;
			}

			ImaEmailNotifier emailNotifier(std::string(gpConf->mSmtpHost), std::string(gpConf->mSmtpUsername), std::string(gpConf->mSmtpPassword));
			emailNotifier.init();
			char msg_body[2048];
			if(bEmailAndImSame) {
				sprintf(msg_body, "Dear %s,\n\n%s %s\n\nRegards,\nIamAliv Team", emailId, MSG_BODY_REG_CONF_CODE, confCode);
			} else {
				sprintf(msg_body, "Dear %s,\n\n%s %s\n\nRegards,\nIamAliv Team", emailId, MSG_BODY_REG_CONF_CODE_ALT, confCode);
			}
//			sprintf(msg_body, "%s is: \"%s\"", MSG_SUB_REG_CONF_CODE, confCode);
			if(false == emailNotifier.notify(MSG_SUB_REG_CONF_CODE, msg_body, emailId)) {
				LOG(error, __FILE__, __LINE__, "Failed to send registration confirmation code to the user");
			} else {
				LOG(debug, __FILE__, __LINE__, "Sent the registration confirmation code to the user");
			}
		} else {
			sprintf(log_msg, "Erroneous message dequeued from the message queue; Message: %s", buf);
			LOG(error, __FILE__, __LINE__, log_msg);
		}
	}
}


void send_user_feedback() {
	LOG(info, __FILE__, __LINE__, "send_user_feedback called");

	char buf[MSGQBUFSZ];
	char senderName[128];
	char senderEmail[128];
	char feedbackSub[128];
	char feedbackBody[512];

	while(gpMqInterface->dequeueFeedbackMsg(buf) == true) {
		char log_msg[1024];
		sprintf(log_msg, "Fetched user feedback from message queue %s", buf);
		LOG(debug, __FILE__, __LINE__, log_msg);
		const char* pBuf = buf;
		const char* p = NULL;

		if((p = strstr(pBuf, "#")) != NULL) {
			size_t len = p - pBuf;
			strncpy(senderName, pBuf, len);
			senderName[len] = '\0';
		} else {
			LOG(error, __FILE__, __LINE__, "Dropped this feedback packet because its errornous");
			return;
		}

		pBuf = p + 1;
		if((p = strstr(pBuf, "#")) != NULL) {
			size_t len = p - pBuf;
			strncpy(senderEmail, pBuf, len);
			senderEmail[len] = '\0';
		} else {
			LOG(error, __FILE__, __LINE__, "Dropped this feedback packet because its errornous");
			return;
		}

		pBuf = p + 1;
		if((p = strstr(pBuf, "#")) != NULL) {
			size_t len = p - pBuf;
			strncpy(feedbackSub, pBuf, len);
			feedbackSub[len] = '\0';
			strcat(feedbackSub, " from ");
			strcat(feedbackSub, senderEmail);
		} else {
			LOG(error, __FILE__, __LINE__, "Dropped this feedback packet because its errornous");
			return;
		}

		strcpy(feedbackBody, p+1);

		ImaEmailNotifier emailNotifier(std::string(gpConf->mSmtpHost), std::string(gpConf->mSmtpUsername), std::string(gpConf->mSmtpPassword));
		emailNotifier.init();
		char msg_body[2048];
		if(false == emailNotifier.notify("kamal.nandan@iamaliv.com", senderName, senderEmail, feedbackSub, feedbackBody)) {
			LOG(error, __FILE__, __LINE__, "Failed to send feedback message...");
		} else {
			LOG(debug, __FILE__, __LINE__, "Sent the feedback message...");
		}
	}
}

int notify_recipients() {
	LOG(debug, __FILE__, __LINE__, "notify_recipients called");

	ImaEmailNotifier emailNotifier(std::string(gpConf->mSmtpHost), std::string(gpConf->mSmtpUsername), std::string(gpConf->mSmtpPassword));
	emailNotifier.init();

	int retVal = 0;
	
	while(true) {
		char log_msg[1024];
		std::vector<ImaInfo*> infoVector;

		if(gpDbInterface->getListOfInfoToSend(infoVector) != 1) {
			LOG(error, __FILE__, __LINE__, "Failed to fetch the list of info to send because of some DB error");
			retVal = -1;
		} else {
			LOG(debug, __FILE__, __LINE__, "Succesfully fetched the list of info to be sent to the respective recipients; Now fecthing the list of recipients for the respective info");
			while(!infoVector.empty()) {
				ImaInfo* pInfo = infoVector.back();
				infoVector.pop_back();
				std::vector<ImaRecipient*> recipientVector;
				if(1 != gpDbInterface->getListOfRecipients(pInfo->mInfoId, recipientVector)) {
					sprintf(log_msg, "Failed to get list of recipients for info id %lu", pInfo->mInfoId);
					LOG(error, __FILE__, __LINE__, log_msg);
				} else {
					sprintf(log_msg, "Fetched the list of recipients for info id %lu", pInfo->mInfoId);
					LOG(debug, __FILE__, __LINE__, log_msg);
					if(recipientVector.size() > 0) {
						emailNotifier.notify(pInfo, recipientVector);
					}
					//TODO: notify via SMS and snail-mail too
					//remove all the elements from the vector
					while(!recipientVector.empty()) {
						ImaRecipient* pRecipient = recipientVector.back();
						recipientVector.pop_back();
						delete pRecipient;
					}
				}
				delete pInfo;
			}
		}

		sprintf(log_msg, "sleeping for %lu minutes", gpConf->mPollingInterval);
		LOG(debug, __FILE__, __LINE__, log_msg);
		sleep(gpConf->mPollingInterval * 60);
	}

	return retVal;	
}


int run() {
	LOG(info, __FILE__, __LINE__, "run called");

	unsigned short num_minutes_per_day = 24 * 60;
	unsigned int sleep_interval = gpConf->mPollingInterval * 30;
	unsigned short sleep_count = 0;
	unsigned int num_sleeps_per_day = num_minutes_per_day / gpConf->mPollingInterval;

	while(true) {
		send_new_passwords();
		send_conf_codes();
		send_user_feedback();
		sleep_count++;
		sleep(sleep_interval);

/*		if(sleep_count >= num_sleeps_per_day) {
			sleep_count = 0;
	//		notify_recipients(); //TODO: later
		} */
	}

	return 0;
}



int
main(int argc, char *argv[]) {
	if (argc < 3) {
		fprintf (stderr, "Usage: %s [-b] [-c conf file name]\n", argv[0]);
		exit (EXIT_FAILURE);
	}

	int nDaemonize = 0;
	int nCh;
	char* pConfFilename = IMA_CONF_FILE;
	while ((nCh = getopt(argc, argv, "bc:")) != -1) {
		switch(nCh) {
			case 'c':
				pConfFilename = optarg;
				break;
			case 'b':
				nDaemonize = 1;
				break;
			case 'h':
			default:
				fprintf (stderr, "Usage: %s [-c config file name] [-h]\n", argv[0]);
				exit(EXIT_FAILURE);
		}
	}

	/* Accessing of the Config file, if the config file exists then parse the config file */
	if (access(pConfFilename, R_OK) != 0) {
		fprintf(stderr, "Conf file doesnt exist");
		exit(EXIT_FAILURE);
	}
	
	if(ima_init_globals(pConfFilename) != 0) {
		fprintf(stderr, "Failed to initialize globals");
		exit(EXIT_FAILURE);
	}

	/* Begin Daemonize if requested */
	if(nDaemonize) {
		if (daemonize(0, 0) == -1) {
			printf( "ERROR - main: unable to daemonize\n");
			exit(EXIT_FAILURE);
		}
	}

	char log_msg[1024];
	sprintf(log_msg, "KN: Logger instance created");
	LOG(debug, __FILE__, __LINE__, log_msg);

//	emailNotifier.notify();
//	emailNotifier.notify();

	run();
	
	return EXIT_SUCCESS;
} 


